<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\UploadedFile;
use Exception;

/**
 * 图片文字识别服务
 *
 * Class OcrService
 * @package App\Services
 * @author klinson <klinson@163.com>
 * @link https://paddlepaddle-pp-ocrv5-online-demo.ms.show
 */
class GradioService
{
    private $baseUrl = 'https://paddlepaddle-pp-ocrv5-online-demo.ms.show/gradio_api/call/predict';
    private $uploadUrl = 'https://paddlepaddle-pp-ocrv5-online-demo.ms.show/gradio_api/upload';

    /**
     * 上传图片文件并获取OCR识别结果
     *
     * @param UploadedFile|string $imageFile 图片文件或本地文件路径或URL
     * @return array
     * @throws Exception
     */
    public function recognizeText($imageFile)
    {
        try {
            // 第一步：上传文件并提交OCR任务
            $eventId = $this->submitOcrJob($imageFile);

            // 第二步：轮询获取OCR结果
            $result = $this->getOcrResult($eventId);

            return [
                'success' => true,
                'event_id' => $eventId,
                'result' => $result
            ];

        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * 提交OCR任务
     *
     * @param UploadedFile|string $imageFile
     * @return string Event ID
     * @throws Exception
     */
    private function submitOcrJob($imageFile)
    {
        // 如果是文件对象或本地文件，先上传到Gradio服务器
        if ($imageFile instanceof UploadedFile || (is_string($imageFile) && file_exists($imageFile))) {
            $uploadedPath = $this->uploadFileToGradio($imageFile);
            $fileData = [
                'path' => $uploadedPath,
                'orig_name' => $imageFile instanceof UploadedFile ? $imageFile->getClientOriginalName() : basename($imageFile),
                'meta' => [
                    '_type' => 'gradio.FileData'
                ]
            ];
        } else {
            // 如果是URL，直接使用
            $fileData = [
                'path' => $imageFile,
//                'url' => $imageFile,
                'meta' => [
                    '_type' => 'gradio.FileData'
                ]
            ];
        }

        // 构建请求数据
        $requestData = [
            'data' => [$fileData]
        ];

        // 发送POST请求
        $response = Http::timeout(30)
            ->withHeaders([
                'Content-Type' => 'application/json'
            ])
            ->post($this->baseUrl, $requestData);

        if (!$response->successful()) {
            throw new Exception('Failed to submit OCR job: ' . $response->body());
        }

        $responseData = $response->json();

        // 提取event_id
        if (!isset($responseData['event_id'])) {
            throw new Exception('No event_id found in response');
        }

        return $responseData['event_id'];
    }

    /**
     * 上传文件到Gradio服务器
     *
     * @param UploadedFile|string $imageFile
     * @return string 服务器上的文件路径
     * @throws Exception
     */
    private function uploadFileToGradio($imageFile)
    {
        if ($imageFile instanceof UploadedFile) {
            // 处理UploadedFile
            $response = Http::timeout(60)
                ->attach('files', $imageFile->getContent(), $imageFile->getClientOriginalName())
                ->post($this->uploadUrl);
        } else {
            // 处理本地文件路径
            if (!file_exists($imageFile)) {
                throw new Exception('Local file not found: ' . $imageFile);
            }

            $response = Http::timeout(60)
                ->attach('files', file_get_contents($imageFile), basename($imageFile))
                ->post($this->uploadUrl);
        }

        if (!$response->successful()) {
            throw new Exception('Failed to upload file to Gradio: ' . $response->body());
        }

        $uploadResult = $response->json();

        if (empty($uploadResult) || !isset($uploadResult[0])) {
            throw new Exception('Invalid upload response from Gradio');
        }

        return $uploadResult[0]; // 返回服务器上的文件路径
    }

    /**
     * 获取OCR识别结果
     *
     * @param string $eventId
     * @return mixed
     * @throws Exception
     */
    private function getOcrResult($eventId)
    {
        $url = $this->baseUrl . '/' . $eventId;
        $maxAttempts = 30; // 最多尝试30次
        $attempt = 0;

        while ($attempt < $maxAttempts) {
            $response = Http::timeout(300)->get($url);

            if ($response->successful()) {
                $data = $response->body();

                // 检查是否是完成状态的响应
                if (strpos($data, 'data:') === 0) {
                    $jsonData = substr($data, 5); // 移除 "data:" 前缀
                    $result = json_decode(trim($jsonData), true);

                    if (json_last_error() === JSON_ERROR_NONE && isset($result['data'])) {
                        return $result['data'];
                    }
                }

                // 如果响应包含"event: complete"，说明任务完成
                if (strpos($data, 'event: complete') !== false) {
                    // 解析最后的数据行
                    $lines = explode("\n", $data);
                    foreach (array_reverse($lines) as $line) {
                        if (strpos($line, 'data:') === 0) {
                            $jsonData = substr($line, 5);
                            $result = json_decode(trim($jsonData), true);
                            if (json_last_error() === JSON_ERROR_NONE) {
                                return $result;
                            }
                        }
                    }
                } else {
                    if (strpos($data, 'event: error') !== false) {
                        throw new \Exception('OCR error：'.$data);
                    }
                }
            }

            $attempt++;
            sleep(2); // 等待2秒后重试
        }

        throw new Exception('OCR recognition timeout after ' . $maxAttempts . ' attempts');
    }

    /**
     * 处理图片文件（用于URL方式，保留兼容性）
     *
     * @param UploadedFile|string $imageFile
     * @return string 文件URL或路径
     * @throws Exception
     */
    private function handleImageFile($imageFile)
    {
        if ($imageFile instanceof UploadedFile) {
            // 如果是上传的文件，保存到临时存储并返回URL
            $filename = time() . '_' . $imageFile->getClientOriginalName();
            $path = $imageFile->storeAs('temp/images', $filename, 'public');
            return asset('storage/' . $path);

        } elseif (is_string($imageFile)) {
            // 如果是本地文件路径
            if (file_exists($imageFile)) {
                // 对于本地文件，需要先上传到可访问的URL
                return $imageFile;
            } elseif (Storage::exists($imageFile)) {
                // 如果是Laravel storage路径
                return Storage::url($imageFile);
            } elseif (filter_var($imageFile, FILTER_VALIDATE_URL)) {
                // 如果是有效的URL
                return $imageFile;
            } else {
                throw new Exception('Image file not found: ' . $imageFile);
            }
        }

        throw new Exception('Invalid image file parameter');
    }

    /**
     * 自定义请求地址进行OCR识别
     *
     * @param string $customUrl 自定义的OCR接口地址
     * @param UploadedFile|string $imageFile 图片文件或本地文件路径或URL
     * @return array
     * @throws Exception
     */
    public function recognizeTextWithCustomUrl($customUrl, $imageFile)
    {
        try {
            // 临时保存原始URL
            $originalUrl = $this->baseUrl;

            // 设置自定义URL
            $this->baseUrl = rtrim($customUrl, '/');

            // 调用标准识别方法
            $result = $this->recognizeText($imageFile);

            // 恢复原始URL
            $this->baseUrl = $originalUrl;

            return $result;

        } catch (Exception $e) {
            // 恢复原始URL
            $this->baseUrl = $originalUrl;

            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    protected function preprocessImage($image)
    {
        // 下载图片到临时文件
        $tempImagePath = $this->downloadImageToTemp($image);

        try {
            // 获取图片信息
            $imageInfo = getimagesize($tempImagePath);
            if (!$imageInfo) {
                throw new Exception('无法获取图片信息');
            }

            $width = $imageInfo[0];
            $height = $imageInfo[1];
            $type = $imageInfo[2];

            // 创建图片资源
            switch ($type) {
                case IMAGETYPE_JPEG:
                    $sourceImage = imagecreatefromjpeg($tempImagePath);
                    break;
                case IMAGETYPE_PNG:
                    $sourceImage = imagecreatefrompng($tempImagePath);
                    break;
                case IMAGETYPE_GIF:
                    $sourceImage = imagecreatefromgif($tempImagePath);
                    break;
                default:
                    throw new Exception('不支持的图片格式');
            }

            if (!$sourceImage) {
                throw new Exception('无法创建图片资源');
            }

            $halfWidth = intval($width / 2);
            $processedImages = [];

            // 第一部分：左半部分，去掉顶部50px
            $cropTop1 = 50;
            $cropHeight1 = $height - $cropTop1;
            if ($cropHeight1 > 0) {
                $image1 = imagecreatetruecolor($halfWidth, $cropHeight1);
                imagecopy($image1, $sourceImage, 0, 0, 0, $cropTop1, $halfWidth, $cropHeight1);

                $tempPath1 = tempnam(sys_get_temp_dir(), 'ocr_part1_') . '.jpg';
                imagejpeg($image1, $tempPath1, 90);
                imagedestroy($image1);
                $processedImages[] = $tempPath1;
            }

            // 第二部分：右半部分，去掉顶部300px
            $cropTop2 = 300;
            $cropHeight2 = $height - $cropTop2;
            if ($cropHeight2 > 0) {
                $image2 = imagecreatetruecolor($halfWidth, $cropHeight2);
                imagecopy($image2, $sourceImage, 0, 0, $halfWidth, $cropTop2, $halfWidth, $cropHeight2);

                $tempPath2 = tempnam(sys_get_temp_dir(), 'ocr_part2_') . '.jpg';
                imagejpeg($image2, $tempPath2, 90);
                imagedestroy($image2);
                $processedImages[] = $tempPath2;
            }

            // 清理资源
            imagedestroy($sourceImage);
            unlink($tempImagePath);

            return $processedImages;

        } catch (Exception $e) {
            // 清理临时文件
            if (file_exists($tempImagePath)) {
                unlink($tempImagePath);
            }
            throw $e;
        }
    }

    /**
     * 兼容旧版本的方法名
     *
     * @param string $imagePath
     * @return string
     * @throws Exception
     */
    public function recognizeImage($imagePath)
    {
        $result = $this->recognizeText($imagePath);
        return $result;

        if ($result['success']) {
            // 如果结果是数组，尝试提取文本内容
            if (is_array($result['result'])) {
                // 根据PaddlePaddle OCR的返回格式处理
                $textArray = [];
                if (isset($result['result'][0]) && is_array($result['result'][0])) {
                    foreach ($result['result'][0] as $item) {
                        if (is_array($item) && isset($item[1])) {
                            $textArray[] = $item[1];
                        }
                    }
                }
                return implode("\n", $textArray);
            }
            return $result['result'];
        } else {
            throw new Exception($result['error']);
        }
    }
}
